module lambda2_optimizer_mod
USE functions_mod
USE parameters_mod
IMPLICIT NONE

CONTAINS
SUBROUTINE lambda2_optimizer(lambda2_out,gov_spend,sim_labor,sim_shocks,sim_types,sim_capital,hbar,wage,shocks,&
                    types,partprod,rate,tr,population,avg_earnings,ss,survive)
INTEGER, intent(in)   :: sim_types(J,simulationsN),sim_shocks(J,simulationsN)
DOUBLE PRECISION,    intent(in)   :: sim_labor(J,simulationsN),sim_capital(J+1,simulationsN),hbar,wage,survive(J)
DOUBLE PRECISION,    intent(in)   :: shocks(shocksN),types(typesN),avg_earnings,ss(typesN,shocksN/2)
DOUBLE PRECISION,    intent(in)   :: partprod,rate,tr,gov_spend,population(J)
DOUBLE PRECISION,    intent(out)  :: lambda2_out
DOUBLE PRECISION :: diff_out



diff_out=brent(0.01D0, lambda0, 1.5D0,tax_differ,.000000001D0,lambda2_out,sim_labor,sim_shocks,sim_types,sim_capital,&
                hbar,wage,shocks,types,partprod,rate,tr,gov_spend,population,avg_earnings,ss,survive)
end subroutine lambda2_optimizer


!This is objective function to find lambda2
DOUBLE PRECISION FUNCTION tax_differ(lambda0_test,sim_labor,sim_shocks,sim_types,sim_capital,hbar,wage,shocks,types,&
    partprod,rate,tr,gov_spend,population,avg_earnings,ss,survive)
    INTEGER, intent(in)   :: sim_types(J,simulationsN),sim_shocks(J,simulationsN)
    DOUBLE PRECISION,    intent(in)   :: sim_labor(J,simulationsN),sim_capital(J+1,simulationsN),hbar,wage,survive(J)
    DOUBLE PRECISION,    intent(in)   :: shocks(shocksN),types(typesN),avg_earnings,ss(typesN,shocksN/2)
    DOUBLE PRECISION,    intent(in)   :: partprod,rate,tr,lambda0_test,gov_spend,population(J)
    DOUBLE PRECISION	::tax_rev,sim_taxespaid(J,simulationsN),rate_use
    INTEGER ::it,s
    !! Taxes
    tax_rev=0.0D0
    sim_taxespaid=0.0D0
    do it=1,simulationsN
        do s=1,Jnr-1
            if(sim_capital(s,it)<0.0D0) then
                if(s==1) then
                    rate_use=rate/survive(1)
                else
                    rate_use=rate/survive(s-1)
                end if
            else
                rate_use=rate
            end if
            if (sim_labor(s,it)<hbar) then
                sim_taxespaid(s,it)=all_taxer2(rate_use*(sim_capital(s,it)+tr),&
                    wage*shocks(sim_shocks(s,it))*types(sim_types(s,it))*epsilon1(s,1)*partprod*sim_labor(s,it),&
                    lambda0_test)
            else
                sim_taxespaid(s,it)=all_taxer2(rate_use*(sim_capital(s,it)+tr),&
                    wage*shocks(sim_shocks(s,it))*types(sim_types(s,it))*epsilon1(s,1)*sim_labor(s,it),lambda0_test)
            end if
            tax_rev=tax_rev+sim_taxespaid(s,it)*population(s)/simulationsN
        end do
        do s=Jnr,J
!            if(rate*(sim_capital(s,it)+tr)+ss>.76D0*avg_earnings) then
!                sim_taxespaid(s,it)=all_taxer2(rate*(sim_capital(s,it)+tr),0.85D0*ss,lambda0_test)
!            elseif(rate*(sim_capital(s,it)+tr)+ss>.56D0*avg_earnings) then
!                sim_taxespaid(s,it)=all_taxer2(rate*(sim_capital(s,it)+tr),0.50D0*ss,lambda0_test)
!            else
                sim_taxespaid(s,it)=all_taxer2(rate*(sim_capital(s,it)+tr),0.0D0,lambda0_test)
!            end if


            tax_rev=tax_rev+sim_taxespaid(s,it)*population(s)/simulationsN
        end do
    end do
    tax_differ=abs(gov_spend-tax_rev)
end FUNCTION tax_differ

DOUBLE PRECISION FUNCTION tax_differ2(lambda0_test,sim_labor,sim_shocks,sim_types,sim_capital,hbar,wage,shocks,types,&
    partprod,rate,tr,gov_spend,population,avg_earnings,ss,survive)
    INTEGER, intent(in)   :: sim_types(J,simulationsN),sim_shocks(J,simulationsN)
    DOUBLE PRECISION,    intent(in)   :: sim_labor(J,simulationsN),sim_capital(J+1,simulationsN),hbar,wage,survive(J)
    DOUBLE PRECISION,    intent(in)   :: shocks(shocksN),types(typesN),avg_earnings,ss(typesN,shocksN/2)
    DOUBLE PRECISION,    intent(in)   :: partprod,rate,tr,lambda0_test,gov_spend,population(J)
    DOUBLE PRECISION	::tax_rev,sim_taxespaid(J,simulationsN),rate_use
    INTEGER ::it,s
    !! Taxes
    tax_rev=0.0D0
    sim_taxespaid=0.0D0
    do it=1,simulationsN
        do s=1,Jnr-1
            if(sim_capital(s,it)<0.0D0) then
                if(s==1) then
                    rate_use=rate/survive(1)
                else
                    rate_use=rate/survive(s-1)
                end if
            else
                rate_use=rate
            end if

            if (sim_labor(s,it)<hbar) then
                sim_taxespaid(s,it)=all_taxer2(rate_use*(sim_capital(s,it)+tr),&
                    wage*shocks(sim_shocks(s,it))*types(sim_types(s,it))*epsilon1(s,1)*partprod*sim_labor(s,it),lambda0_test)
            else
                sim_taxespaid(s,it)=all_taxer2(rate_use*(sim_capital(s,it)+tr),&
                    wage*shocks(sim_shocks(s,it))*types(sim_types(s,it))*epsilon1(s,1)*sim_labor(s,it),lambda0_test)
            end if
            tax_rev=tax_rev+sim_taxespaid(s,it)*population(s)/simulationsN
        end do
        do s=Jnr,J
!            if(rate*(sim_capital(s,it)+tr)+ss>.76D0*avg_earnings) then
!                sim_taxespaid(s,it)=all_taxer2(rate*(sim_capital(s,it)+tr),0.85D0*ss,lambda0_test)
!            elseif(rate*(sim_capital(s,it)+tr)+ss>.56D0*avg_earnings) then
!                sim_taxespaid(s,it)=all_taxer2(rate*(sim_capital(s,it)+tr),0.5D0*ss,lambda0_test)
!            else
                sim_taxespaid(s,it)=all_taxer2(rate*(sim_capital(s,it)+tr),0.0D0,lambda0_test)
!            end if


            tax_rev=tax_rev+sim_taxespaid(s,it)*population(s)/simulationsN
        end do
    end do
    tax_differ2=(gov_spend-tax_rev)
end FUNCTION tax_differ2




      DOUBLE PRECISION FUNCTION brent(ax,bx,cx,func,tol,xmin,sim_labor,sim_shocks,sim_types,sim_capital,hbar,wage,&
                    shocks,types,partprod,rate,tr,gov_spend,population,avg_earnings,ss,survive)
USE nrtype; USE nrutil, ONLY : nrerror
IMPLICIT NONE
    INTEGER, intent(in)   :: sim_types(J,simulationsN),sim_shocks(J,simulationsN)
    DOUBLE PRECISION, INTENT(IN)    :: ax,bx,cx,tol
    DOUBLE PRECISION,    intent(in)   :: sim_labor(J,simulationsN),sim_capital(J+1,simulationsN),hbar,wage,survive(J)
    DOUBLE PRECISION,    intent(in)   :: shocks(shocksN),types(typesN),avg_earnings,ss(typesN,shocksN/2)
    DOUBLE PRECISION,    intent(in)   :: partprod,rate,tr,gov_spend,population(J)
    DOUBLE PRECISION, INTENT(OUT)   :: xmin
INTEGER, PARAMETER          :: ITMAX=500
DOUBLE PRECISION, PARAMETER ::CGOLD=0.3819660D0,ZEPS=1.0e-3_sp*epsilon(ax)
INTEGER                     ::iter
DOUBLE PRECISION            :: a,b,d,e,etemp,fu,fv,fw,fx,p,q,r,tol1,tol2,u,v,w,x,xm
DOUBLE PRECISION :: func
a=min(ax,cx)
b=max(ax,cx)
v=bx
w=v
x=v
e=0.0
fx=func(x,sim_labor,sim_shocks,sim_types,sim_capital,hbar,wage,shocks,types,partprod,&
                    rate,tr,gov_spend,population,avg_earnings,ss,survive)
fv=fx
fw=fx
do iter=1,ITMAX
    xm=0.5D0*(a+b)
    tol1=tol*abs(x)+ZEPS
    tol2=2.0D0*tol1
    if (abs(x-xm) <= (tol2-0.5D0*(b-a))) then
        xmin=x
        brent=fx
        RETURN
    end if
    if (abs(e) > tol1) then
        r=(x-w)*(fx-fv)
        q=(x-v)*(fx-fw)
        p=(x-v)*q-(x-w)*r
        q=2.0D0*(q-r)
        if (q > 0.0D0) p=-p
        q=abs(q)
        etemp=e
        e=d
        if (abs(p) >= abs(0.5D0*q*etemp) .or. &
            p <= q*(a-x) .or. p >= q*(b-x)) then
            e=merge(a-x,b-x, x >= xm )
            d=CGOLD*e
        else
            d=p/q
            u=x+d
            if (u-a < tol2 .or. b-u < tol2) d=sign(tol1,xm-x)
        end if
    else
        e=merge(a-x,b-x, x >= xm )
        d=CGOLD*e
    end if
    u=merge(x+d,x+sign(tol1,d), abs(d) >= tol1 )
    fu=func(u,sim_labor,sim_shocks,sim_types,sim_capital,hbar,wage,shocks,types,partprod,&
                    rate,tr,gov_spend,population,avg_earnings,ss,survive)
    if (fu <= fx) then
        if (u >= x) then
            a=x
        else
            b=x
        end if
        call shft(v,w,x,u)
        call shft(fv,fw,fx,fu)
    else
        if (u < x) then
            a=u
        else
            b=u
        end if
        if (fu <= fw .or. w == x) then
            v=w
            fv=fw
            w=u
            fw=fu
        else if (fu <= fv .or. v == x .or. v == w) then
            v=u
            fv=fu
        end if
    end if
end do
call nrerror('brent lambda: exceed maximum iterations')
CONTAINS
!BL
SUBROUTINE shft(a,b,c,d)
    DOUBLE PRECISION, INTENT(OUT)   :: a
    DOUBLE PRECISION, INTENT(INOUT) :: b,c
    DOUBLE PRECISION, INTENT(IN)    :: d
a=b
b=c
c=d
END SUBROUTINE shft
END FUNCTION brent












end module lambda2_optimizer_mod


